package com.toe.user.webapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.toe.common.exception.ToeServiceException;
import com.toe.common.pojo.domain.ToeAuthenticationInfo;
import com.toe.common.restful.JsonPage;
import com.toe.common.restful.StateEnum;
import com.toe.common.utils.*;
import com.toe.pojo.dto.user.UserCodeDTO;
import com.toe.pojo.dto.user.UserDTO;
import com.toe.pojo.dto.user.UserPasswordDTO;
import com.toe.pojo.entity.user.UserUsertbl;
import com.toe.pojo.vo.user.UserUserVO;
import com.toe.user.webapi.mapper.UserUsertblMapper;
import com.toe.user.service.UserUsertblService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 陶涛
 * @since 2022-07-19
 */
@DubboService
@Service
@Slf4j
public class UserUsertblServiceImpl extends ServiceImpl<UserUsertblMapper, UserUsertbl> implements UserUsertblService {

    @Autowired
    private UserUsertblMapper usertblMapper;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private UserUsertblMapper userMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 查询出所有没有被禁用的用户的id
     *
     * @return
     */
    @Override
    public List<Long> listAllUserId() {
        return usertblMapper.listAllUserId();
    }

    // 平台分页查询用户列表
    @Override
    public JsonPage<UserUserVO> getUserListByPage(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<UserUserVO> list = usertblMapper.queryUserList();
        return JsonPage.restPage(new PageInfo<>(list));
    }

    @Override
    public void removeUserById(Long id) {
        int rows = usertblMapper.deleteUserById(id);
        if (rows != 1) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_BUSY, "删除用户失败");
        }
    }

    // 修改is_enable字段进行封号
    @Override
    public void forbidUserById(Long id) {
        int rows = usertblMapper.updateIsEnable(id);
        if (rows != 1) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_BUSY, "该账户封号失败");
        }
    }

    @Override
    public void recoverUserById(Long id) {
        int rows = usertblMapper.releaseIsEnable(id);
        if (rows != 1) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_BUSY, "该账户解封失败");
        }
    }

    @Override
    public String sentCode(String phone) {
        //发送验证码并保存到redis
        String code = AliYunSmsUtils.sendCodeSms(phone);
        redisTemplate.opsForValue().set(CODE_KEY+phone,code, 3,TimeUnit.MINUTES);
        System.out.println("发送的code>>>>"+code);
        return code;
    }

    @Override
    public Boolean check(UserCodeDTO codeDTO) {
        String realCode = redisTemplate.opsForValue().get(CODE_KEY + codeDTO.getPhone());
        if(realCode==null){
            throw new ToeServiceException(StateEnum.ERR_CODE,"验证码已过期，请重新发送！");
        }
        return realCode.equals(codeDTO.getCode());
    }

    @Override
    public void reg(UserDTO userDTO) {
        //判断注册时验证码是否则正确
        String code = userDTO.getCode();
        String realCode = redisTemplate.opsForValue().get(CODE_KEY + userDTO.getPhone());
        if (!StringUtils.hasText(realCode)){
            throw new ToeServiceException(StateEnum.ERR_CODE,"验证码已失效！");
        }
        if (!realCode.equals(code)){
            throw new ToeServiceException(StateEnum.ERR_CODE,"验证码错误");
        }
        //创建用户的账号
        UserUsertbl user = new UserUsertbl();
        BeanUtils.copyProperties(userDTO, user);
        //默认启用该用户
        user.setIsEnable(1);
        //创建用户的账号
        SnowFlakeUtil id=new SnowFlakeUtil(0,1,1661159488999L);
        user.setAccount(id.getSnowFlakeNumber());
        //设置用户生日
        user.setBirthday(user.getBirthday());
        //赋值空属性为默认值
        if (!StringUtils.hasText(user.getSex())) {
            user.setSex("男");
        }
        if (!StringUtils.hasText(user.getAvatar())) {
            user.setAvatar("默认头像.jpeg");
        }
        if (!StringUtils.hasText(user.getBackground())) {
            user.setBackground("默认背景");
        }
        if (!StringUtils.hasText(user.getDescription())) {
            user.setDescription("这个人很懒,什么描述也没有~");
        }
        //设置初始密码
        String initialPassword = null;
        if (!StringUtils.hasText(user.getPassword())){
            int i = RandomUtils.nextInt(100000, 999999);
            initialPassword="toe"+i;
            user.setPassword(initialPassword);
        }
        //
        //判断当前用户名是否存在
        UserUsertbl userUsername = userMapper.selectOne(new QueryWrapper<UserUsertbl>().eq("username", user.getUsername()));
        if (!(userUsername == null)) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY, "该用户名已存在!");
        }
        //判断当前电话号码是否存在
        UserUsertbl userPhone = userMapper.selectOne(new QueryWrapper<UserUsertbl>().eq("phone", user.getPhone()));
        if (!(userPhone == null)) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY, "该电话号码已被使用!");
        }
        //判断当前电子邮箱是否被使用
        UserUsertbl userEmail = userMapper.selectOne(new QueryWrapper<UserUsertbl>().eq("email", user.getEmail()));
        if (!(userEmail == null)) {
            throw new ToeServiceException(StateEnum.ERR_BAD_QUERY, "该电子邮箱已被使用!");
        }

        String finalInitialPassword = initialPassword;
        Thread thread=new Thread(() -> {
            EmailUtil.sendMessage(user.getEmail(),"启能toe【初始密码】","【启能toe】您的初始密码是: "+ finalInitialPassword +" ,打死也别告诉别人哦！");
            log.info("邮件发送成功！");
        });
        thread.start();
        //通过用户填写的身高体重计算用户bmi
        Double height = user.getHeight();
        Double weight = user.getWeight();
        if (height == null) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR, "身高不能为空!");
        }
        if (weight == null) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR, "体重不能为空!");
        }
        Double bmi = weight / (Math.pow(height, 2));
        //保留两位小数
        DecimalFormat format = new DecimalFormat("#0.00");
        String bmiStr = format.format(bmi);
        user.setBmi(Double.valueOf(bmiStr));
        //将密码进行加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        boolean insert = save(user);
        System.out.println("注册: " + insert);
        if (!insert) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR, "注册失败,服务器忙,请稍后再试!");
        }

    }



    @Override
    public UserUserVO getUserDetail() {
        //获取当前登录用户的id
        Long userId = getUserId();
        //查询用户详细信息
        QueryWrapper<UserUsertbl> wrapper = new QueryWrapper<>();
        wrapper.eq("id", userId);
        UserUsertbl userDetail = getOne(wrapper);
        UserUserVO userVO = new UserUserVO();
        BeanUtils.copyProperties(userDetail, userVO);
        log.info("userDetail>>> {}", userDetail);
        log.info("userVO>>> {}", userVO);
        Integer age = (int) TimeUtil.getAge(userDetail.getBirthday());
        userVO.setAge(age);
        return userVO;
    }

    @Override
    public boolean updateUserDetail(UserDTO userDTO) {
        //获取当前登录用户的id
        Long userId = getUserId();
        //更新用户数据
        UserUsertbl user = new UserUsertbl();
        BeanUtils.copyProperties(userDTO, user);
        Double height = user.getHeight();
        Double weight = user.getWeight();
        if(height!=null||weight!=null) {
            user.setBmi(weight/Math.pow(height,2));
        }
        log.info("前端传来的用户信息>>");
        UpdateWrapper<UserUsertbl> updateWrapper = new UpdateWrapper();
        updateWrapper.eq("id", userId);
        boolean update = update(user, updateWrapper);
        return update;
    }

    /**
     * 上传头像
     *
     * @param avatar 头像
     */
    @Override
    public String updateAvatar(MultipartFile avatar){
        String path = "E://toe-avatar";
        String newAvatar="";
        try {
            newAvatar = FileUtils.upload(path, avatar);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Long userId = getUserId();
        UserUsertbl user = usertblMapper.selectById(userId);
        String oldAvatar = user.getAvatar();
        //流操作
        Thread thread=new Thread(() -> {
            //删除老头像
            File file=new File(path+"/"+oldAvatar);
            if (file.exists()&&!oldAvatar.equals("默认头像.jpeg")){
                boolean delete = file.delete();
                log.info("是否已经删除老头像: {}",delete);
            }
        });
        thread.start();
        UserUsertbl userEntity=new UserUsertbl();
        userEntity.setId(getUserId());
        userEntity.setAvatar(newAvatar);
        usertblMapper.updateById(userEntity);
        return newAvatar;
    }

    @Override
    public void updatePassword(UserPasswordDTO passwordDTO) {
        Long userId = getUserId();
        PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(passwordDTO.getPassword());
        UserUsertbl user=new UserUsertbl();
        user.setId(userId);
        user.setPassword(encode);
        usertblMapper.updateById(user);
    }

    private String getPath(){
        StringBuilder builder= null;
        try {
            String  uri = UserUsertblServiceImpl.class.getClassLoader().getResource(".").toURI().toString();
            String substring = uri.substring(uri.indexOf("/") + 1, uri.indexOf("/target/"));
            builder = new StringBuilder(substring);
            builder.append("/src/main/resources/static/avatar");
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        return builder.toString();
    }

    public Long getUserId() {
        Object credentials = SecurityContextHolder.getContext().getAuthentication().getCredentials();
        ToeAuthenticationInfo authenticationInfo = (ToeAuthenticationInfo) credentials;
        return authenticationInfo.getId();
    }

}
